/**
 * @FileName: CcbController.java
 * @Author
 * @Description:
 * @Date 2016年5月9日 下午5:29:41
 * @CopyRight ZTE Corporation
 */
package cn.hpclub.server.controller.h5;

import java.util.HashMap;
import java.util.Map;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.aop.Before;
import com.jfinal.core.ActionKey;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;

import CCBSign.RSASig;
import cn.hpclub.server.ccbpay.CcbConfig;
import cn.hpclub.server.ccbpay.CcbSubmit;
import cn.hpclub.server.ccbpay.JSEscape;
import cn.hpclub.server.ccbpay.ServiceType;
import cn.hpclub.server.constant.ClientApiConstant;
import cn.hpclub.server.constant.Constant;
import cn.hpclub.server.constant.H5ApiConstant;
import cn.hpclub.server.model.CityCounter;
import cn.hpclub.server.model.CmccOrder;
import cn.hpclub.server.model.RechargeOrder;
import cn.hpclub.server.service.CcbService;
import cn.hpclub.server.service.CcbService.CheckCcbOrderStatusException;
import cn.hpclub.server.service.CmccPackageService;
import cn.hpclub.server.service.CmccRechargeService;
import cn.hpclub.server.service.OpenAccountService;
import cn.hpclub.server.service.RechargeOrderService;
import cn.hpclub.server.util.DESCrypto;
import cn.hpclub.server.util.SysCodeValueUtils;
import cn.hpclub.server.util.SystemConfigUtil;

public class CcbController extends BaseH5Controller{

    // @Fields OUT_DATA :

    // @Fields PAY_ACCEPT :

    // @Fields DETAIL_MSG :

    private static final String DETAIL_MSG   = "DETAIL_MSG";

    private static final String PAY_ACCEPT   = "PAY_ACCEPT";

    private static final String OUT_DATA     = "OUT_DATA";

    private static final String RETURN_CODE  = "RETURN_CODE";

    private static final String ROOT         = "ROOT";

    private static final Logger logger       = LoggerFactory.getLogger(CcbController.class);
    private static final String ORDER_ID     = "orderid";
    private static final String RAW_STR      = "rawStr";

    private static final String ORDER_STATUS = "order";
    private static final String PAY_STATUS   = "pay";
    private static final String MSG          = "msg";

    // @ActionKey(value = "test")
    // public void test() throws IOException{
    // JSONObject jo = setResponseObj(H5ApiConstant.ResultCode.FAIL_CODE,
    // H5ApiConstant.Msg.FAIL, null);
    // try{
    // String requestStr = SocketUtil.buildXML(getPara("orderid"),
    // getPara("amount"));
    // System.out.println("requestStr:" + requestStr);
    // if(requestStr == null){
    // jo = setResponseObj(H5ApiConstant.ResultCode.FAIL_CODE, "参数不正确", null);
    // renderText(jo.toString());
    // return;
    // }
    // String response = SocketUtil.request(requestStr, "127.0.0.1", 2212);
    // System.out.println("response:" + response);
    // if((response == null) || ("".equals(response))){
    // jo = setResponseObj(H5ApiConstant.ResultCode.FAIL_CODE, "Socket返回数据异常",
    // null);
    // } else{
    // String jsonStr = XmlConverUtil.xmltoJson(response);
    // logger.debug("result:" + response);
    // jo = new JSONObject(jsonStr);
    // }
    // }
    // catch(Exception e){
    // logger.error("exception:" + e.getMessage());
    // jo = setResponseObj(H5ApiConstant.ResultCode.EXCEPTION_CODE,
    // e.getMessage(), null);
    // }
    //
    // renderText(jo.toString());
    //
    // }

    // @ActionKey(value = "ccbtest")
    // public void ccbtest(){
    // String html = "处理数据异常，提交支付失败";
    // try{
    // int orderId = new Random().nextInt(1000000);
    // String orderIdStr = String.valueOf(orderId);
    //
    // Map<String, String> sPara = new HashMap<String, String>();
    //
    // // 这两个，根据订单userid从表里面读取对应地区的柜台ID和pub数据
    // sPara.put(CcbConfig.Key.POSID, "861041666");
    // sPara.put(CcbConfig.Key.PUB, "103eeaeb3af4ce00a627bc63020111");
    //
    // // 支付方式。建行填""，银联填"UnionPay"
    // int payType = getParaToInt("type");
    // System.out.println("payType:" + payType);
    // if(payType == 15){
    // sPara.put(CcbConfig.Key.GATEWAY, CcbConfig.PayType.CCB_PAY);
    // } else if(payType == 16){
    // sPara.put(CcbConfig.Key.GATEWAY, CcbConfig.PayType.UNION_PAY);
    // }
    //
    // // 订单信息，包括订单ID，金额，订单商品名称，订单办理人姓名，都是必填项
    // sPara.put(CcbConfig.Key.ORDERID, orderIdStr);
    // sPara.put(CcbConfig.Key.PAYMENT, "0.01");
    // sPara.put(CcbConfig.Key.PROINFO, JSEscape.escape("充值缴费"));
    // sPara.put(CcbConfig.Key.REGINFO, JSEscape.escape("测试员"));
    //
    // // remark1填业务类型，1-充值缴费；2-选号入网。用于ccb支付完成后页面结果显示处根据不同业务跳转到不同的分支去。
    // sPara.put(CcbConfig.Key.REMARK1, ServiceType.RECHARGE.getValue());
    //
    // html = CcbSubmit.buildRequest(sPara);
    // System.out.println("html:" + html);
    // }
    // catch(Exception e){
    // html = "处理数据异常，提交支付失败";
    // e.printStackTrace();
    // }
    //
    // renderHtml(html);
    //
    // }

    // @ActionKey(value = "test")
    // @Before(Tx.class)
    // public void test() throws IOException{
    //
    // String orderIdStr = getParaByKey("orderid");
    // String amount = getParaByKey("amount");
    // String suc = getParaByKey("result");

    // boolean result = updateRechargeOrder(orderIdStr, amount,
    // "1".equals(suc) ? true : false);
    //
    // System.out.println("if to recharge:" + result);

    // boolean result = updatePackageOrder(orderIdStr, amount,
    // "1".equals(suc) ? true : false);
    //
    // System.out.println("if to package:" + result);

    // // renderHtml();
    // //
    // getResponse().sendRedirect("http://120.27.128.207/dzg/website/ccbresult.html?type=1&result=1");
    //
    // openAccount(orderIdStr);
    // }
    //
    // public void test() throws IOException{
    // // new OpenAccountService().saveSalesPromotion(getPara("o"),
    // // getPara("x"), "ok!");
    // openAccount(getPara("o"));
    //
    // }

    /**
     * @Title: packagePay
     * @Description:客户端选号入网新增订单时返回该链接。客户端在订单提交成功时，通过webview调用该链接， 进去wap支付请求。
     *                                                            wap支付成功后，
     *                                                            将在cbcnotify处理db状态变更和选号入网操作
     *                                                            。用户在“返回商户”时，
     *                                                            通过cbcreturn进行订单业务办理结果的查询。
     * 
     *                                                            关于rawstr的说明，
     *                                                            由于选号入网开户需要两个流程
     *                                                            ，1）获取rawstr
     *                                                            2）开户。
     *                                                            第一步获取rawstr需要用客户端选号获取的参数
     *                                                            ，比较难以处理，
     *                                                            直接客户端申请rawstr传递过来做开户处理。
     */
    @ActionKey(value = "pkgpay")
    public void packagePay(){
        String html = "处理数据异常，提交支付失败";
        logger.info("package pay request in");
        String orderId = getParaByKey("o");
        String rawStr = getParaByKey("r");

        logger.info("package pay request oid:" + orderId);

        try{
            // 客户端传orderid时做了DES编码和urlencode编码
            orderId = java.net.URLDecoder.decode(DESCrypto.decrypt(orderId, ClientApiConstant.CONSTANT_DES_KEY),
                                                 ClientApiConstant.ENCODING);

            logger.info("package pay request oid:" + orderId);

            // 保存rawstr，用于后续的办理业务。如果保存失败，也就是没有继续支付的必要了，因为支付了业务办理也会失败。
            if(!saveRawStr(orderId, rawStr)){
                throw new Exception("服务器处理错误，保存数据失败");
            }

            Map<String, String> sPara = Order2Map(orderId);
            html = CcbSubmit.buildRequest(sPara);

            logger.debug("html:" + html);
        }
        catch(Exception e){
            html = e.getMessage();
            e.printStackTrace();
        }
        finally{
            logger.debug("pay html:" + html);
            renderHtml(html);
        }

    }

    private boolean saveRawStr(String orderId, String rawStr) throws Exception{
        if(StrKit.isBlank(rawStr)){
            throw new Exception("支付请求失败，参数异常");
        }

        CmccOrder order = CmccOrder.dao.getOrderInfo(orderId);
        if(order == null){
            throw new Exception("支付请求失败，订单号:" + orderId + "不存在");
        }

        order.set(CmccOrder.RAW_STR, rawStr);

        return order.update();

    }

    /**
     * @Title: Order2Map
     * @Description:TODO
     * @param orderId
     * @return
     * @throws Exception
     *             Map<String,String>
     */

    private Map<String, String> Order2Map(String orderId) throws Exception{
        Record order = CmccOrder.dao.getOrder(orderId);
        if(order == null){
            throw new Exception("支付请求失败，订单号:" + orderId);
        }

        if(CmccOrder.PAID == order.getInt(CmccOrder.PAY_STATUS)){
            throw new Exception("支付请求失败：订单" + orderId + "已支付");
        }

        Map<String, String> sPara = new HashMap<String, String>();

        // 这两个，根据订单userid从表里面读取对应地区的柜台ID和pub数据
        sPara.put(CcbConfig.Key.POSID, CityCounter.getPosId(order));
        sPara.put(CcbConfig.Key.PUB, CityCounter.getPub30(order));

        // 支付方式。建行填""，银联填"UnionPay"
        int payType = order.getInt(CmccOrder.PAY_PLAT);
        logger.debug("payType:" + payType);
        if(payType == Constant.PayPlat.CCB){
            sPara.put(CcbConfig.Key.GATEWAY, CcbConfig.PayType.CCB_PAY);
        } else if(payType == Constant.PayPlat.UNION_PAY){
            sPara.put(CcbConfig.Key.GATEWAY, CcbConfig.PayType.UNION_PAY);
        }

        // 订单信息，包括订单ID，金额，订单商品名称，订单办理人姓名，都是必填项.中文要进行escape编码
        sPara.put(CcbConfig.Key.ORDERID, orderId);
        sPara.put(CcbConfig.Key.PAYMENT, String.valueOf(order.getDouble(CmccOrder.ORDER_AMOUNT)));
        sPara.put(CcbConfig.Key.PROINFO, JSEscape.escape(order.getStr(CmccOrder.PACKAGE_NAME)));
        sPara.put(CcbConfig.Key.REGINFO, JSEscape.escape(order.getStr(CmccOrder.USERNAME)));

        // remark1填业务类型，1-充值缴费；2-选号入网。用于ccb支付完成后页面结果显示处根据不同业务跳转到不同的分支去。
        sPara.put(CcbConfig.Key.REMARK1, ServiceType.PACKAGE.getValue());
        return sPara;

    }

    String getPub32ByOrderId(ServiceType type, String orderId){

        if(type == ServiceType.RECHARGE){
            Record orderRecord = RechargeOrderService.service.getRechargeOrderByOrderId(orderId);

            // "30819c300d06092a864886f70d010101050003818a003081860281806c5ce0ed0655b741d546503f041f1c919bb3bbbf88d7d1549258208619d96df352cd385fb7699a13c4d95c020ab55e5723e64d783180974d6605a6d7db3579b4c8d0751d9e917631e45844a5fd1bf3dba2aa7958b4f823401b46db3274173063b886b1dfd9056235bef55d56811f593e787d8a26103eeaeb3af4ce00a627bc63020111";
            return orderRecord.getStr("pub");

        } else if(type == ServiceType.PACKAGE){
            Record order = CmccOrder.dao.getOrder(orderId);
            return order.getStr("pub");
        }

        return "";
    }

    ServiceType getServiceType(String value){
        if(value.equals(ServiceType.RECHARGE.getValue())){
            return ServiceType.RECHARGE;
        } else if(value.equals(ServiceType.PACKAGE.getValue())){
            return ServiceType.PACKAGE;
        } else{
            return ServiceType.UNKOWN;
        }
    }

    boolean updateOrder(ServiceType type, String orderId, String amount, boolean result){
        if(type == ServiceType.RECHARGE){
            // return CmccRechargeService.service.updateRechargeOrder(orderId,
            // amount, result);
            return CmccRechargeService.service.updateRechargeOrderNew(orderId, amount, result);
        } else if(type == ServiceType.PACKAGE){
            return CmccPackageService.service.updatePackageOrder(orderId, amount, result);
        }
        // 其他的类型抛弃
        return false;

    }

    @ActionKey(value = "cbcnotify")
    public void cbcnotify() throws Exception{

        logger.info("cbcnotify in test");

        RSASig rsa = new RSASig();

        String orderId = getParaByKey(CcbConfig.Key.ORDERID);
        String remark1 = getParaByKey(CcbConfig.Key.REMARK1);
        ServiceType type = getServiceType(remark1);

        logger.info("cbcnotify in service type:" + type);

        logger.info("cbcnotify in id:" + orderId);

        if(!orderExist(type, orderId)){
            // 订单不存在，直接return
            logger.error("订单号" + orderId + "不存在");
            return;
        }

        rsa.setPublicKey(getPub32ByOrderId(type, orderId));

        String sign = getSign();
        String src = getNotifySrc();
        // String src = getReturnSrc();

        if(rsa.verifySigature(sign, src)){

            logger.info("Sign OK");

            String amount = getParaByKey(CcbConfig.Key.PAYMENT);
            String result = getParaByKey(CcbConfig.Key.SUCCESS);
            if(updateOrder(type, orderId, amount, ("Y".equals(result) ? true : false))){
                // 处理业务
                if(type == ServiceType.RECHARGE){
                    logger.info("recharge in");
                    // 调中移充值接口
                    cmccRecharge(orderId, RechargeOrder.RESULT_TYPE_FIRST_RECHARGE);// 1-首次充值、2-二次充值、3-查询更新、4-查询充值
                    // renderText("do");
                } else if(type == ServiceType.PACKAGE){
                    // 调中移选号入网接口
                    logger.info("openAccount in");
                    openAccount(orderId);
                    // renderText("do");
                }

            } else{
                // 已经办理过了或者支付状态不对，不进行办理业务。
                // renderText("donot do");
            }

        } else{
            // 验签失败的，认为是非法请求。不处理
            logger.error("Sign fail:" + orderId);
            // renderText("Sign fail:" + orderId);
        }

    }

    /**
     * @Title: cmccRecharge
     * @Description:充值缴费业务
     * @param orderId
     * @param rechargeType
     */
    private void cmccRecharge(String orderId, int rechargeType){
        new RechargeOrderService().cmccRechargeAndRefund(orderId, rechargeType);
    }

    /**
     * 
     * 
     * @Title: openAccount
     * @Description:办理选号入网业务。rawstr采用申请支付时上传的rawstr
     * @param orderId
     *            void
     */

    private void openAccount(String orderId){
        new OpenAccountService().openAccountAndRefund(orderId);
    }

    /**
     * 
     * 
     * @Title: orderExist
     * @Description:TODO
     * @param type
     * @param orderId
     *            void
     */
    private boolean orderExist(ServiceType type, String orderId){
        if(type == ServiceType.RECHARGE){
            return RechargeOrder.dao.exist(orderId);
        } else{
            return CmccOrder.dao.exist(orderId);
        }

    }

    /**
     * @Title: getNotifySrc
     * @Description:TODO
     * @return String
     */

    private String getNotifySrc(){
        String src = "POSID=" + getParaByKey(CcbConfig.Key.POSID) + "&BRANCHID=" + getParaByKey(CcbConfig.Key.BRANCHID)
                + "&ORDERID=" + getParaByKey(CcbConfig.Key.ORDERID) + "&PAYMENT=" + getParaByKey(CcbConfig.Key.PAYMENT)
                + "&CURCODE=" + getParaByKey(CcbConfig.Key.CURCODE) + "&REMARK1=" + getParaByKey(CcbConfig.Key.REMARK1)
                + "&REMARK2=" + getParaByKey(CcbConfig.Key.REMARK2) + "&ACC_TYPE="
                + getParaByKey(CcbConfig.Key.ACC_TYPE) + "&SUCCESS=" + getParaByKey(CcbConfig.Key.SUCCESS) + "&TYPE="
                + getParaByKey(CcbConfig.Key.TYPE) + "&REFERER=" + getParaByKey(CcbConfig.Key.REFERER) + "&CLIENTIP="
                + getParaByKey(CcbConfig.Key.CLIENTIP);
        // 当前还没有usrmsg; 如果系统设置设置了返回到账日期，则accdate参与计算。手机支付默认不返回。
        // + "&ACCDATE=" + getParaByKey("ACCDATE")+ "&USRMSG=" +
        // getParaByKey("USRMSG")
        logger.info("acc type:" + getParaByKey(CcbConfig.Key.ACC_TYPE));
        logger.info("acc date:" + getParaByKey(CcbConfig.Key.ACCDATE));
        logger.debug("src:" + src);
        return src;
    }

    /**
     * @Title: getSign
     * @Description:TODO
     * @return String
     */

    private String getSign(){
        String sign = getParaByKey(CcbConfig.Key.SIGN);
        logger.info("sign:" + sign);
        return sign;
    }

    private int getUserId(ServiceType type, String orderId){
        if(type == ServiceType.RECHARGE){
            return RechargeOrder.dao.getUserId(orderId);
        } else{
            return CmccOrder.dao.getUserId(orderId);
        }

    }

    private String getToken(ServiceType type, String orderId){
        if(type == ServiceType.RECHARGE){
            return RechargeOrder.dao.getToken(orderId);
        } else{
            return CmccOrder.dao.getToken(orderId);
        }

    }

    @ActionKey(value = "cbcreturn")
    // @Before(Tx.class)
    public void cbcreturn() throws Exception{

        logger.info("cbcreturn in");
        RSASig rsa = new RSASig();

        String orderId = getParaByKey(CcbConfig.Key.ORDERID);
        String remark1 = getParaByKey(CcbConfig.Key.REMARK1);
        ServiceType type = getServiceType(remark1);

        logger.info("cbcreturn in,service type:" + type);

        if(!orderExist(type, orderId)){
            // 订单不存在
            renderHtml("非法链接，订单号不存在");
            return;
        }

        rsa.setPublicKey(getPub32ByOrderId(type, orderId));

        String sign = getSign();
        String src = getReturnSrc();

        if(rsa.verifySigature(sign, src)){
            logger.info("Sign OK");

            int result = "Y".equals(getParaByKey(CcbConfig.Key.SUCCESS)) ? 1 : 2;
            int userId = getUserId(type, orderId);
            String token = getToken(type, orderId);

            // 根据业务类型和结果，给出提示语。
            // type:1-充值，2-选号入网，其他-ccbresult会报业务类型错误。result:1-ok,2-failed
            String resultUrl = SystemConfigUtil.getSystemConfig().getHostPrefix() + getRequest().getContextPath()
                    + "/website/ccbresult.html?type=" + type.getValue() + "&result=" + result + "&orderid=" + orderId
                    + "&u=" + userId + "&t=" + token;
            // TODO:del 8080
            logger.debug("resultUrl:" + resultUrl);
            getResponse().sendRedirect(resultUrl);

        } else{
            // 验签失败的，认为是非法请求。不处理
            logger.error("Sign fail,order:" + orderId);
            renderHtml("非法链接:" + orderId);
        }

    }

    /**
     * @Title: getReturnSrc
     * @Description:TODO
     * @return String
     */

    private String getReturnSrc(){
        String src = "POSID=" + getParaByKey(CcbConfig.Key.POSID) + "&BRANCHID=" + getParaByKey(CcbConfig.Key.BRANCHID)
                + "&ORDERID=" + getParaByKey(CcbConfig.Key.ORDERID) + "&PAYMENT=" + getParaByKey(CcbConfig.Key.PAYMENT)
                + "&CURCODE=" + getParaByKey(CcbConfig.Key.CURCODE) + "&REMARK1=" + getParaByKey(CcbConfig.Key.REMARK1)
                + "&REMARK2=" + getParaByKey(CcbConfig.Key.REMARK2) + "&SUCCESS=" + getParaByKey(CcbConfig.Key.SUCCESS)
                + "&TYPE=" + getParaByKey(CcbConfig.Key.TYPE) + "&REFERER=" + getParaByKey(CcbConfig.Key.REFERER)
                + "&CLIENTIP=" + getParaByKey(CcbConfig.Key.CLIENTIP);

        // 当前还没有usrmsg; 如果系统设置设置了返回到账日期，则accdate参与计算。手机支付默认不返回。
        // + "&ACCDATE=" + getParaByKey("ACCDATE")+ "&USRMSG="+
        // getParaByKey("USRMSG");

        logger.debug("src:" + src);
        logger.info("acc type:" + getParaByKey(CcbConfig.Key.ACC_TYPE));
        logger.info("acc date:" + getParaByKey(CcbConfig.Key.ACCDATE));
        return src;
    }

    String getParaByKey(String key){
        String value = null;
        try{
            value = getPara(key);
            if(value == null){
                value = "";
            }
        }
        catch(Exception e){
            e.printStackTrace();
            logger.error("key not passed:" + key);
            value = "";
        }

        return value;

    }

    /**
     * @Title: getOrderStatus
     * @Description:获取选号入网业务办理结果
     */
    @ActionKey(value = "getOrderStatus")
    @Before(Tx.class)
    public void getOrderStatus(){

        String orderId = getParaByKey("orderid");
        logger.info("getOrderStatus:" + orderId);
        if(orderId == null){
            JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.FAILED, "订单号为空",
                                               ClientApiConstant.Msg.EMPTY);
            renderText(resObj.toString());
            return;
        }

        if(orderId.startsWith(CcbService.XHRW_SUFFIX_K)){
            if(!CmccOrder.dao.exist(orderId)){
                JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.FAILED, "订单不存在",
                                                   ClientApiConstant.Msg.EMPTY);
                renderText(resObj.toString());
                return;
            }
            JSONObject obj = getCmccOrderStatus(orderId);
            JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.SUCCESS_CODE, "", obj);
            renderText(resObj.toString());
            // return;

        } else if(orderId.startsWith(CcbService.CZJF_SUFFIX_C)){
            if(!RechargeOrder.dao.exist(orderId)){
                JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.FAILED, "订单不存在",
                                                   ClientApiConstant.Msg.EMPTY);
                renderText(resObj.toString());
                return;
            }
            JSONObject obj = getRechargeOrderStatus(orderId);
            JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.SUCCESS_CODE, "", obj);
            renderText(resObj.toString());
            // return;

        } else{
            JSONObject resObj = setResponseObj(ClientApiConstant.ResultCode.FAILED, "暂不支持该订单类型",
                                               ClientApiConstant.Msg.EMPTY);
            renderText(resObj.toString());
            // return;
        }

    }

    /**
     * @Title: getCmccOrderDesc
     * @Description:1）针对于order_status，0/1/5/6/7/8，需要正确显示结果的描述。 2）对于1,6，
     *                                                         当APP退费功能开启时，
     *                                                         描述需要有“ 即时退费”
     *                                                         3）对于0,7,8，
     *                                                         当定时退费功能开启时，描述需要有“
     *                                                         开户结果可能有延迟，请刷新。
     *                                                         当天22:
     *                                                         50之前尚未成功的订单，将于23:
     *                                                         00执行退费。”
     *                                                         4)若先失败，再更新成功，
     *                                                         则不按照成功提示，不提示退费
     * @param order
     * @return String
     */
    private String getCmccOrderDesc(CmccOrder order){
        int status = order.getInt(CmccOrder.ORDER_STATUS);
        String msg = "";

        if(status == CmccOrder.ORDER_SUBMITED){
            msg = "未知状态";

        } else if(status == CmccOrder.ORDER_NOT_REQUEST){

            msg = "请求异常，未发起开户办理，办理失败。";

        } else if(status == CmccOrder.ORDER_SUC){
            // 成功的情况下，返回办理成功
            msg = "开户成功";

        } else if(status == CmccOrder.ORDER_FAILED){

            msg = order.getStr(CmccOrder.OPERATED_DESC) == null ? "" : order.getStr(CmccOrder.OPERATED_DESC);

        } else if(status == CmccOrder.ORDER_REQUEST_NOT_BACK){

            msg = "请求开户接口时，返回网络异常。";

        } else if(status == CmccOrder.ORDER_REQUEST_RESULT_PARSE_ERROR){

            msg = "请求开户接口时，返回数据无法解析。";

        } else{
            msg = "未知业务办理状态";
        }

        if(CmccOrder.REFUND_FAILED == order.getInt(CmccOrder.PAY_STATUS)){
            String refundMsg = order.getStr(CmccOrder.DESC_DETAILS) == null ? "" : order.getStr(CmccOrder.DESC_DETAILS);
            msg += "<br>" + refundMsg;
        }
        return msg;

    }

    /**
     * @Title: getRechargeOrderDesc
     * @Description:1）针对于order_status，0/1/5/6/7/8，需要正确显示结果的描述。 2）对于1,6，
     *                                                         当APP退费功能开启时，
     *                                                         描述需要有“ 即时退费”
     *                                                         3）对于0,7,8，
     *                                                         当二次充值功能开启时，描述需要有“
     *                                                         充值结果可能有延迟，请刷新。
     *                                                         当天22:
     *                                                         50之前尚未成功的订单，将于23:
     *                                                         00执行二次充值。”
     *                                                         4)若先失败，再更新成功，
     *                                                         则不按照成功提示，不提示二次充值
     * @param order
     * @return String
     */
    private String getRechargeOrderDesc(RechargeOrder order){
        int status = order.getInt(RechargeOrder.ORDER_STATUS);
        String msg = "";

        if(status == RechargeOrder.ORDER_SUBMITED){
            msg = "未知状态";
        } else if(status == RechargeOrder.ORDER_NOT_REQUEST){

            msg = "请求异常，未发起充值，充值失败。";

        } else if(status == RechargeOrder.ORDER_SUC){
            // 成功的情况下，返回办理成功
            msg = "充值成功";

        } else if(status == RechargeOrder.ORDER_FAILED){

            msg = order.getStr(RechargeOrder.OPERATED_DESC) == null ? "" : order.getStr(RechargeOrder.OPERATED_DESC);

            // 失败的情况下，返回业务办理失败结果说明+退费说明

        } else if(status == RechargeOrder.ORDER_REQUEST_NOT_BACK){

            msg = "请求充值接口时，返回网络异常。";

        } else if(status == RechargeOrder.ORDER_REQUEST_RESULT_PARSE_ERROR){

            msg = "请求充值接口时，返回数据无法解析。";

        } else{
            msg = "未知业务办理状态";
        }

        if(RechargeOrder.REFUND_FAILED == order.getInt(RechargeOrder.PAY_STATUS)){
            String refundMsg = order.getStr(RechargeOrder.DESC_DETAILS) == null ? ""
                    : order.getStr(RechargeOrder.DESC_DETAILS);
            msg += "<br>" + refundMsg;
        }

        return msg;

    }

    private JSONObject getCmccOrderStatus(String orderId){

        CmccOrder order = CmccOrder.dao.getOrderStatusInfo(orderId);

        JSONObject obj = new JSONObject();

        obj.put(PAY_STATUS, order.getStr("pay_state"));
        obj.put(ORDER_STATUS, getCmccOrderState(order));
        obj.put(MSG, getCmccOrderDesc(order));

        return obj;
    }

    private String getCmccOrderState(CmccOrder order){
        int payStatus = order.getInt(CmccOrder.PAY_STATUS);
        int orderStatus = order.getInt(CmccOrder.ORDER_STATUS);
        String orderState = order.getStr("order_state");

        switch(payStatus){
            case CmccOrder.PAID:{
                if((orderStatus == CmccOrder.ORDER_FAILED) || (orderStatus == CmccOrder.ORDER_NOT_REQUEST)){
                    String appRefundMsg = "";
                    // 已支付，办理返回明确错误原因的，并且自动开关打开的，提示即将退回银行卡
                    if(SysCodeValueUtils.isSwitchOpen(SysCodeValueUtils.CCB_APP_REFUND)){
                        appRefundMsg = "<br>费用即将自动退回到缴费银行卡，请刷新和查收";
                    }
                    return orderState + appRefundMsg;

                } else if((orderStatus == CmccOrder.ORDER_SUBMITED) || (orderStatus == CmccOrder.ORDER_REQUEST_NOT_BACK)
                        || (orderStatus == CmccOrder.ORDER_REQUEST_RESULT_PARSE_ERROR)){
                    String scheduledRefundMsg = "";
                    if(SysCodeValueUtils.isSwitchOpen(SysCodeValueUtils.CCB_SCHEDULED_REFUND)){
                        scheduledRefundMsg = "<br>开户结果可能有延迟，请刷新。当天22:50之前尚未成功的已支付订单，将于23:00执行退费";
                    }
                    return orderState + scheduledRefundMsg;
                }
            }
            default:
                return orderState;

        }

    }

    private JSONObject getRechargeOrderStatus(String orderId){

        RechargeOrder order = RechargeOrder.dao.getOrderStatusInfo(orderId);

        JSONObject obj = new JSONObject();

        obj.put(PAY_STATUS, order.getStr("pay_state"));
        obj.put(ORDER_STATUS, getRechargeOrderState(order));
        obj.put(MSG, getRechargeOrderDesc(order));

        return obj;
    }

    private String getRechargeOrderState(RechargeOrder order){
        int payStatus = order.getInt(RechargeOrder.PAY_STATUS);
        int orderStatus = order.getInt(RechargeOrder.ORDER_STATUS);
        String orderState = order.getStr("order_state");

        switch(payStatus){
            case RechargeOrder.PAID:{
                if((orderStatus == RechargeOrder.ORDER_FAILED) || (orderStatus == RechargeOrder.ORDER_NOT_REQUEST)){
                    String appRefundMsg = "";
                    // 已支付，办理返回明确错误原因的，并且自动开关打开的，提示即将退回银行卡
                    if(SysCodeValueUtils.isSwitchOpen(SysCodeValueUtils.CCB_APP_REFUND)){
                        appRefundMsg = "<br>费用即将自动退回到缴费银行卡，请刷新和查收";
                    }
                    return orderState + appRefundMsg;

                } else if((orderStatus == RechargeOrder.ORDER_SUBMITED)
                        || (orderStatus == RechargeOrder.ORDER_REQUEST_NOT_BACK)
                        || (orderStatus == RechargeOrder.ORDER_REQUEST_RESULT_PARSE_ERROR)){

                    String reRechargeMsg = "";
                    if(SysCodeValueUtils.isSwitchOpen(SysCodeValueUtils.CCB_RE_RECHARGE)){
                        reRechargeMsg = "<br>充值结果可能有延迟，请刷新。当天22:50之前尚未成功的订单，将于23:00执行二次充值";
                    }
                    return orderState + reRechargeMsg;
                }
            }
            default:
                return orderState;

        }

    }

    public static class UpdateRechargeOrderStatusException extends Exception{
        private static final long serialVersionUID = 6498418588195332455L;

        public UpdateRechargeOrderStatusException(String message){
            super(message);
        }
    }

    public static class SaveToSalesPromossionException extends Exception{
        private static final long serialVersionUID = 6498418588195332455L;

        public SaveToSalesPromossionException(String message){
            super(message);
        }
    }

    /**
     * 消费记录中查询接口：去建行查询相应订单的支付状态，并根据返回的支付状态，或去补充值，或返回
     * 
     * @Title: searchOrder
     * @Description:TODO void
     */
    public void searchOrder(){
        logger.info("----ccb searchOrder in----");
        JSONObject jo = setResponseObj(H5ApiConstant.ResultCode.FAIL_CODE, H5ApiConstant.Msg.FAIL,
                                       H5ApiConstant.Msg.EMPTY);
        String orderId = null;
        try{
            // 验证用户有效性
            String userId = getPara("userId", null);
            String token = getPara("token", null);
            String validResult = validRequestParams(userId, token);
            if(StrKit.notBlank(validResult)){
                renderText(validResult);
                return;
            }

            orderId = getPara("orderId", null);// 订单号

            logger.info(orderId);

            jo = CcbService.service.searchOrder(orderId, RechargeOrder.RESULT_TYPE_SEARCH_RECHARGE);

        }
        catch(CheckCcbOrderStatusException e){// 该异常不是真正的异常，单独捕获，并封装成失败的结果
            e.printStackTrace();
            logger.error("CheckCcbOrderStatusException: " + e.getMessage() + orderId);
            jo = setResponseObj(H5ApiConstant.ResultCode.FAIL_CODE, "建行返回状态：" + e.getMessage(),
                                H5ApiConstant.Msg.EMPTY);
        }
        catch(Exception e){// 所有的异常在这里封装结果
            e.printStackTrace();
            logger.error("ccb查询订单异常：" + e.getMessage() + "：" + orderId);
            jo = setResponseObj(H5ApiConstant.ResultCode.EXCEPTION_CODE, e.getMessage(), H5ApiConstant.Msg.EMPTY);
        }

        // for test
        // logger.info(jo.toString());
        // renderText(jo.getString(H5ApiConstant.Key.MESSAGE));

        renderText(jo.toString());
    }

    // 后续客户端订单有退款功能时调用
    // public void refund(){
    // JSONObject jo = CcbService.service.appRefund(getPara("orderId"),
    // getPara("amount"));
    // renderText(jo.toString());
    // }

    // 单元测试方法
    // public void test(){
    // String result = "Error:getHttpByPostBody exception";
    // try{
    // JSONObject data = new JSONObject(result);
    // // save2SalesPromossion("C1701190000280111264232", "", false,
    // // "单元测试", "单元测试");
    // }
    // catch(Exception e){
    // // e.printStackTrace();
    // logger.error("Exception:" + e.getMessage());
    // try{
    // updateRechargeOrderStatus("C1701190000280111264232", "", 6,
    // "充值失败(" + result + "):调用充值接口异常或者服务器异常导致,"
    // + (StrKit.notBlank(e.getMessage())
    // ? e.getMessage().substring(0,
    // (e.getMessage().length() >= 100
    // ? 100
    // : e.getMessage().length()))
    // : ""));
    // }
    // catch(UpdateRechargeOrderStatusException e1){
    // e1.printStackTrace();
    // logger.error("UpdateRechargeOrderStatusException: " + e.getMessage());
    // }
    // }
    //
    // }

    // /**
    // *
    // * @Title: cmccRechargeTest
    // * @Description: 充值缴费接口测试
    // */
    // public void cmccrechargetest(){
    // String orderId = getPara("orderId");
    // new RechargeOrderService().cmccRechargeAndRefund(orderId, 1);
    // renderText("");
    // }
    // /**
    // *
    // * @Title: cmccopenaccounttest
    // * @Description:选号入网接口测试 void
    // */
    // public void cmccopenaccounttest(){
    // String orderId = getPara("orderId");
    // new OpenAccountService().openAccountAndRefund(orderId);
    // renderText("");
    // }
    // 调用API写入移动业务数据测试
    // public void test(){
    // new OpenAccountService().saveSalesPromotion(getPara("orderId"),
    // getPara("cmccOrderId"), "test");
    // renderText("");
    // }

    // /**
    // * 建行查询支付失败订单定时任务调用接口
    // */
    // @Before(Tx.class)
    // public void runnerRechargeOrder(){
    // JSONObject result = new JSONObject();
    // try{
    // String orderId = DESCrypto.decrypt(getParaByKey(RechargeOrder.ORDER_ID),
    // "ccbquery");// 解密订单
    // if(RechargeOrder.dao.exist(orderId)){
    // result = CcbService.service.searchOrder(orderId, 5);//
    // 1-首次充值、2-二次充值、3-查询更新、4-手动查询充值、5-自动查询充值
    // renderText(result.toString());
    // }
    // }
    // catch(Exception e){
    // logger.info("接口出错", e.getMessage());
    // }
    // renderText(result.toString());
    // }
}
